Skip to content

fix(drivers): expose device limits and measured control response - #149

Merged
frahlg merged 5 commits into
mainfrom
feat/control-feedback
Oct 1, 2026
Merged

frahlg merged 5 commits into
mainfrom
feat/control-feedback

Conversation

@frahlg

@frahlg frahlg commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

An Easee charger can cap charging at 8 A while FTW asks for 16 A. Pixii can accept a write and report a different setpoint on a later poll. These changes expose those facts during normal operation, so Core can tell whether a device does what FTW asked.

Pixii 2.1.7 reads the setpoint outside troubleshooting mode and reports AC power for control separately from its DC battery reading. AC power (40083) is SunSpec's generator frame, like the setpoint, so it is negated into site signs; a following battery read as the wrong direction before. Easee Cloud 1.3.6 reports its static current ceiling and age separately from the dynamic offer. It keeps the source timestamp when the cloud repeats an observation and marks the unchanged value control_power_confirmed while the cloud still hears from the charger, so a steady charge stays measured instead of raising a lost-control alarm. Missing power or source time cannot confirm a command's effect.

Sungrow 1.5.10 reports the active forced setpoint from its existing holding-register read. It claims a separate meter (power_origin="external_meter") on known hybrid models only when the meter reads power or phase current; a meterless install reads zero and claims none. Failed meter or PV reads cannot supply control evidence. No extra Modbus calls.

A failed settings read does not refresh the limit's age. Existing polling cadence and write policy stay unchanged.

Paired with srcfl/ftw#1474 (pins d74ace6) and srcfl/ftw-webapp#75.

Validation: make check (4,754 passed, 913 skipped). Focused: sungrow 88 passed, easee_cloud 38 passed, pixii 104 passed, including a meterless hybrid, a confirmed steady Easee value and Pixii's AC sign. A private ARM64 box run confirmed the Sungrow setpoint readback and fresh measured power. Pixii hardware checks remain, for both signs; keep draft. Known gaps: SH-RS and SH-T share the hybrid claim without manual evidence, and Sungrow's 5 kW write clamp reads as a changed setpoint when Core sends more. Existing Heishamon PRs #60 and #66 remain untouched.

🤖 Generated with Claude Code

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-01T14:36:30.596418Z df00393 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 405ca9a927

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread drivers/lua/pixii.lua Outdated
local battery = {
w = bat_w,
setpoint_w = setpoint_pixii_w and -setpoint_pixii_w,
control_power_w = acw_regs and ac_w,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Convert Pixii AC feedback to site signs

When the battery discharges, register 40083 is the SunSpec inverter AC-power value, whose positive direction is inverter output; other Model 103 consumers such as drivers/lua/solaredge_pv.lua:203-243 negate this register before emitting the repository's site sign. Passing ac_w through here therefore reverses command feedback in both charge and discharge, so Core will compare a site-signed setpoint with an oppositely signed response. Emit -ac_w and test both power directions.

AGENTS.md reference: AGENTS.md:L71-L73

Useful? React with 👍 / 👎.

Comment thread drivers/lua/pixii.lua Outdated
Comment on lines +477 to +478
control_power_w = acw_regs and ac_w,
control_power_available = acw_regs ~= nil,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require a valid scale factor for AC feedback

If the separate read of register 40084 fails while 40083 succeeds, read_sf silently substitutes scale factor zero, yet this code reports the resulting raw register value as available control power. A transient failure can therefore make Core treat a value that is off by the device's power multiplier as fresh command feedback; availability should require successful reads of both the value and its scale factor, preferably from one block read.

AGENTS.md reference: AGENTS.md:L17-L20

Useful? React with 👍 / 👎.

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@frahlg
frahlg marked this pull request as draft September 29, 2026 11:40
frahlg and others added 2 commits September 29, 2026 19:33
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Paired with srcfl/ftw#1474, which now reads control_power_confirmed.

Easee's cloud records power only on change, so a steady charge kept an old
source time and Core raised a lost-control alarm during normal charging.
The driver now marks the unchanged value confirmed while the cloud still
hears from the charger; the source time stays for distinct samples.

Pixii's AC power (40083) is SunSpec generator frame, like its setpoint, so
control_power_w is now negated into site signs. A following battery read as
the wrong direction before. Hardware has not verified either sign yet.

Sungrow claims external_meter only when the meter reads power or phase
current; a meterless install reads zero and claims none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
frahlg added a commit to srcfl/ftw that referenced this pull request Oct 1, 2026
Moves the bundled snapshot to srcfl/device-drivers#149 at d74ace6a: Easee
marks a steady value confirmed while the cloud hears from the charger,
Pixii's control power leaves SunSpec's generator frame, and Sungrow claims
a separate meter only when one reads power or phase current.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@frahlg
frahlg marked this pull request as ready for review October 1, 2026 14:33

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: df003935ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread drivers/lua/sungrow.lua

host.emit("pv", {
w = -pv_w, -- negative = generation (EMS convention)
control_power_available = pv_regs ~= nil or mppt_regs ~= nil,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require the selected PV fallback to answer

When the primary PV register returns zero because of the documented firmware quirk and the MPPT read times out, this or still marks control power available even though the fallback ladder emits zero without a usable source. Core can consequently accept a false zero-power response while the array is still generating; availability should require whichever source actually determined pv_w to have answered.

AGENTS.md reference: AGENTS.md:L18-L20

Useful? React with 👍 / 👎.

Comment thread drivers/lua/sungrow.lua
-- power and zero phase current, so it claims no separate meter.
local meter_origin = nil
local meter_reads = mw_regs ~= nil and (meter_w ~= 0 or l1_a + l2_a + l3_a > 0)
if model_family == "hybrid" and meter_reads then meter_origin = "external_meter" end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Limit external-meter evidence to documented Sungrow families

This condition covers every device classified as a hybrid, including the advertised SH-RS and SH-T families, but the only upstream evidence added in manifests/sungrow.yaml:56-59 is the SH-RT manual. On the unevidenced families, any nonzero 5600/current reading is therefore promoted to an independent external meter that Core may use to confirm control, without proof that those registers represent a separate sensor rather than inverter-derived data; restrict the claim to evidenced models or add model-specific register/HIL evidence.

AGENTS.md reference: AGENTS.md:L17-L20

Useful? React with 👍 / 👎.

@frahlg
frahlg merged commit 424f1e5 into main Oct 1, 2026
5 checks passed
@frahlg
frahlg deleted the feat/control-feedback branch October 1, 2026 16:03
frahlg added a commit to srcfl/ftw that referenced this pull request Oct 1, 2026
* feat(control): show command limits and measured response tiers

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* fix(control): require fresh source samples for measured confirmation

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* feat(control): compare site response curves with measured flow changes

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* fix(control): classify commanded devices and qualify solar response

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Recognize relayed physical meters and show measured time gaps

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Verify control per device with unknown flows in the residual

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Put control proof on device bubbles and open evidence on tap

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Keep control evidence quiet on overview bubbles

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Open device controls first with measured evidence below

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Keep control evidence below the device controls in the vision

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Separate measured power evidence from target fulfilment

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Stop charging full batteries and explain the pause

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Answer "Are we in control?" in every mode and name the evidence

Control proof restarted on every command that differed by 100 W, so modes
that retune the battery each tick showed "waiting" most of the time and never
warned when the battery stopped following. A cloud charger never reached
measured proof, a kettle after a confirmed step removed the confirmation, and
a battery tapering near full raised a warning.

Retuning now continues one measurement record. Each reading is compared with
the commands that could still be in force during the device's response time;
only a material step (500 W or the tolerance) starts a new comparison. A
source's declared power_max_age_s sets its freshness everywhere. The site
comparison freezes once its post-step window is complete. A charge shortfall
at 90% SoC or more, or a discharge shortfall at 10% or less, is information.

Core now states the answer: status (following, waiting, limited,
not_following, no_contact, not_controlled), severity (info, warning, alarm),
evidence (accepted, measured, confirmed), confirmed_at_ms and readings_fresh.
Lost measured proof becomes readings_lost. Site numbers live in
site_evidence and are omitted when not computed. Trace tests replay
self-consumption, an ignored battery, a kettle, a taper and a cloud charger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Show the control answer first in each device sheet

A tap on a bubble opened the manual hold form with "Charge 3000 W"
preselected, and the answer sat folded below it in tier labels. The sheet
now starts with "Are we in control?": one status, one sentence with the
measured numbers and, when the owner can act, the next step. "How FTW knows"
lists sent, accepted, measured and confirmed evidence, with numbers and the
response curve folded inside. Manual override folds below; Stop sits in the
active-hold banner.

The overview stays quiet while FTW is in control. Only Core's warning and
alarm draw a mark, an amber triangle or a red disc, and a combined bubble
keeps the worst. The Values view lists each controlled device with its
answer. Words come from Core's status, severity and reason; a test fails
when Core can emit a reason without words. The EV status line keeps power
first. The shared module holds no DOM code; the box renderer lives in
control-feedback-view.js.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Describe control status and the evidence receipt

Replace the tier ladder and bubble layout rules in VISION.md with the
status the owner sees and the receipt behind it. Keep the paragraph about
battery learning, but after the roadmap table so the Later row stays in it.
The changeset now describes the shipped behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Describe measured changes in words instead of signs

The app never shows a bare minus sign. Device, grid and unexplained changes
now read "toward discharge", "toward export" or "more drawn".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Keep change-only sources current while they confirm the value

Easee's cloud records power only when it changes; a steady charge kept an
old source time, so measured proof lapsed and the lost-control alarm fired
during normal charging. A driver may now set control_power_confirmed when
the source still hears from the device and the value is unchanged. Core
treats that reading as a measurement at the time it arrived: it keeps a
steady charge measured, and a charger that holds its old power after a new
target now reads as not following instead of waiting forever. Sources that
do not confirm keep the old rule: a repeated sample adds nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

* Pin drivers with confirmed Easee power and site-signed Pixii AC

Moves the bundled snapshot to srcfl/device-drivers#149 at d74ace6a: Easee
marks a steady value confirmed while the cloud hears from the charger,
Pixii's control power leaves SunSpec's generator frame, and Sungrow claims
a separate meter only when one reads power or phase current.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>

---------

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant